/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.suai.system.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.suai.dao.Buffer;
import org.suai.dao.impl.BufferImpl;
import org.suai.system.QueueSystem;
import org.suai.dao.Package;
import org.suai.dao.impl.BufferAloha;
import org.suai.dao.impl.PackageImpl;
import org.suai.dao.impl.SystemStatistic;
import org.suai.manager.StatisticManager;

/**
 *
 * @author awm
 */
public class AlohaSystemImpl implements QueueSystem{
    private int userCount;
    private double intensity;
    private Buffer buffer;
    private Set packagesForService;
    private int systemNumber;

    private StatisticManager instance;
    private boolean isConflict = false;

    public AlohaSystemImpl(int systemNumber, double lamda, int userCount) {
        this.systemNumber = systemNumber;
        //buffer  = new BufferAloha();
        buffer = new BufferImpl();
        packagesForService = new HashSet();
        instance = StatisticManager.getInstance();
        this.intensity = lamda;
        this.userCount = userCount;
    }

    public void setUserCounts(int userCounts) {
        this.userCount = userCounts;
    }

    public void setIntensity(double intensity) {
        this.intensity = intensity;
    }

    public int getUserCounts() {
        return userCount;
    }

    public double getIntensity() {
        return intensity;
    }

    /**
     * Generate package for all users and return packages for service
     */
    public void generatePackages() {
        int busyUsers = getBusyUsers();
        
        for(int i = 0; i < userCount; i++) {
            Package item = generatePackage(i, busyUsers);
            if( item != null ) {
                buffer.setPackage(i, item);
                instance.createPackage(this);
            }
        }

        //return buffer.getPackagesForService();
    }

    private int getBusyUsers() {
        int result = 0;
        for (int i = 0; i < userCount; i++) {
            if(!buffer.isFree(i)) {
                result++;
            }
        }
        return result;
    }

    private Package generatePackage(int userNumber, int busyUsers) {
        if( /*!buffer.isFree(userNumber) || */ !isPackageCreate(busyUsers)) {
            return null;
        }

        return new PackageImpl( systemNumber, userNumber );

    }

    private boolean isPackageCreate(int busyUsers) {
        //double p = intensity / (userCount - busyUsers);
        double p = intensity / userCount ;

        if( Math.random() < p ) {
            return true;
        }
        return false;
    }

    /**
     * Set package for service from all systems.
     * @param packages - list of package for service
     */
    @Override
    public void setOuterPackages(List packages) {
        //if (isConflict == false)
        packagesForService.addAll(packages);


    }

    @Override
    public void servicePackages() {
        //System.out.println(buffer);

        if( packagesForService.size() == 0 ) {
            isConflict = false;
            return;
        }

        
        if( packagesForService.size() == 1 ) {
            Package pkg = (Package)packagesForService.toArray()[0];
            servicePackage(pkg);
            isConflict = false;
            packagesForService.remove(pkg);
        } else if (isConflict){
            List resolvePkgs = resolveConflict( packagesForService );
            //if(resolvePkgs.size() == 0) {
                //isConflict = false;
                //packagesForService = new HashSet();
            /*} else*/ if(resolvePkgs.size() == 1) {
                Package pkg = (Package)resolvePkgs.get(0);
                servicePackage(pkg);
                packagesForService.remove(pkg);// = new HashSet();
                
                if(packagesForService.size() == 0)
                    isConflict = false;
            } 
        } else {
            isConflict = true;
        }
    }

    private void servicePackage(Package pkg) {
        if(pkg.getSystemNumber() == this.systemNumber) {
            buffer.servicePackage( pkg.getOwnerNumber() );
                instance.servicePackage(this);
            } else {
                instance.deletePackage(this);
            }
    }

    private List resolveConflict(Set packageForService) {
        List result = new LinkedList();
        double p = 1.0 / packageForService.size();

        for(Object pkg : packageForService.toArray()){
            double rand = Math.random();
            if(rand < p) {
                result.add(pkg);
            }
        }
        

        //int index = (int)(rand / p);

        //return (Package)(packageForService.toArray()[index]);
        return result;
    }

    @Override
    public int getSystemNumber() {
        return systemNumber;
    }

    @Override
    public List getPackagesForService() {
        return buffer.getPackagesForService();
    }
}